<?php
require_once('simpletest/autorun.php');
require_once('../templar.php');
require_once('templar_testing_resources.php');


/**********************************************************************
 * Test of successful TemplarCascadeFramework instantiation.
 *********************************************************************/
class TestInstantiation extends TemplarUnitTestCase {
    function testInstantiateMainClass() {
        $mock_obj = new stdClass();
        $cascade = new TemplarCascadeFramework($mock_obj);
        $this->assertNotNull($cascade);
    }
}

/**********************************************************************
 * Test to verify that built-in file extensions have corresponding
 * built-in type definitions.
 *********************************************************************/
class ValidateRegisteredTypes extends CascadeUnitTestCase {
    function testExtensionsHaveMatchingTypes() {
        $cascade = $this->cascade;
        foreach ($cascade->registeredExtensions as $type) {
            $has_key = array_key_exists($type, $cascade->registeredTypes);
            $this->assertTrue($has_key);
        }
    }
    function testBuiltInTypeDefinitions() {
        $cascade = $this->cascade;
        foreach ($cascade->registeredTypes as $key=>$type) {
            $this->assertEqual(count($type), 3); // 3 item assoc array
            $this->assertEqual($key, $type['name']);
            $this->assertTrue(is_callable($type['handler']));
            $this->assertTrue((is_int($type['max_kb']) && $type['max_kb']>=0)
                    || is_null($type['max_kb']), "Must be zero, NULL or positive integer");
        }
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestGetFileType extends CascadeUnitTestCase {
    function testBuiltInTypes() {
        $type = $this->cascade->getFileType('dummy_path/index.html');
        $this->assertEqual($type['name'], 'markup');
        $this->assertTrue(is_callable($type['handler']));
        $this->assertEqual($type['handler'], 'file_get_contents');

        $type = $this->cascade->getFileType('index.php');
        $this->assertEqual($type['name'], 'code');
        $this->assertTrue(is_callable($type['handler']));
        $this->assertEqual($type['handler'], array($this->cascade, '_getMarkupFromCode'));

        $type = $this->cascade->getFileType('dummy_path/index.txt');
        $this->assertEqual($type['name'], 'text');
        $this->assertTrue(is_callable($type['handler']));
        $this->assertEqual($type['handler'], array($this->cascade, '_getMarkupFromText'));
    }
    function testUnknownType() {
        $type = $this->cascade->getFileType('dummy_path/index.xyz');
        $this->assertNull($type['name']);
        $this->assertNull($type['handler']);
        $this->assertNull($type['max_kb']);
    }
}

/**********************************************************************
 * Test getPath method.
 *********************************************************************/
class TestGetPath extends TemplarUnitTestCase {
    protected $cascade = NULL; // gets instance of TemplarCascadeFramework
    function setUp() {
        TemplarUnitTestCase::setUp();
        $templar = &new MockTemplarPHP();
        $templar->envFileRoot = getcwd() . '/'; // set mock value
        $this->cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
        /* create dummy files */
        file_put_contents('file_a.html', '');
        file_put_contents('file_b.php', '');
        file_put_contents('file_b.html', '');
    }
    function tearDown() {
        /* delete dummy files */
        @unlink('file_a.html');
        @unlink('file_b.php');
        @unlink('file_b.html');
        TemplarUnitTestCase::tearDown();
    }
    function testGetPathWithBasicRequests() {
        $path = $this->cascade->getPath('file_a');
        $this->assertEqual($path, 'file_a.html');

        $path = $this->cascade->getPath('file_b');
        $this->assertEqual($path, 'file_b.php'); // php is before html

        $path = $this->cascade->getPath('xyz');
        $this->assertNull($path);
    }
    function testGetPathWithFullExtension() {
        $path = $this->cascade->getPath('file_b.php');
        $this->assertEqual($path, 'file_b.php');

        $path = $this->cascade->getPath('file_b.html');
        $this->assertEqual($path, 'file_b.html');
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestFormatText extends CascadeUnitTestCase {
    function testFormatTextDefaults() {
        $text = $this->cascade->formatText('This is a test.');
        $this->assertEqual($text, '<tt>This is a test.</tt>');

        $text = $this->cascade->formatText('Foo, bar & baz.');
        $this->assertEqual($text, '<tt>Foo, bar &amp; baz.</tt>');
    }
    function testFormatTextOptions() {
        /* escaping-off (and default preformatting-off) */
        $text = $this->cascade->formatText('some <b>bold</b> text', FALSE);
        $this->assertEqual($text, '<tt>some <b>bold</b> text</tt>');

        /* escaping-on, preformatting-on */
        $text = $this->cascade->formatText('some <b>bold</b> text', TRUE, TRUE);
        $this->assertEqual($text, '<pre>some &lt;b&gt;bold&lt;/b&gt; text</pre>');

        /* escaping-off, preformatting-on */
        $text = $this->cascade->formatText('some <b>bold</b> text', FALSE, TRUE);
        $this->assertEqual($text, '<pre>some <b>bold</b> text</pre>');
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestPathToTitle extends CascadeUnitTestCase {
    function testBasicPathToTitle() {
        $cascade = $this->cascade;

        $title = $cascade->pathToTitle('RAINYDAY.html');
        $this->assertEqual($title, 'RAINYDAY'); // remove extension

        $title = $cascade->pathToTitle('photos/RAINYDAY');
        $this->assertEqual($title, 'RAINYDAY'); // remove folder

        $title = $cascade->pathToTitle('./photos/RAINYDAY');
        $this->assertEqual($title, 'RAINYDAY'); // remove folder

        $title = $cascade->pathToTitle('/photos/RAINYDAY');
        $this->assertEqual($title, 'RAINYDAY'); // remove folder

        $title = $cascade->pathToTitle('RAINY_DAY');
        $this->assertEqual($title, 'RAINY DAY'); // underscore to space

        $title = $cascade->pathToTitle('rainy day');
        $this->assertEqual($title, 'Rainy Day'); // to upper case

        $title = $cascade->pathToTitle('photos/rainy_day.html');
        $this->assertEqual($title, 'Rainy Day'); // all transforms
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestWrapInHtml extends CascadeUnitTestCase {
    function testWrapInHtmlBehavior() {
        /* basic check for leading markup */
        $markup = $this->cascade->wrapInHtml('<p>Hello Content</p>');
        $this->assertPattern('/<!DOCTYPE html.*/', $markup);

        /* default, no title */
        $markup = $this->cascade->wrapInHtml('<p>Hello Content</p>');
        $this->assertPattern('/<title><\/title>/', $markup);
        $this->assertNoPattern('/<h1><\/h1>/', $markup);

        /* default, including title */
        $markup = $this->cascade->wrapInHtml('<p>Hello Content</p>', 'Hello Title');
        $this->assertPattern('/<title>Hello Title<\/title>/', $markup);
        $this->assertPattern('/<h1>Hello Title<\/h1>/', $markup);

        /* heading-off, including title */
        $markup = $this->cascade->wrapInHtml('<p>Hello Content</p>', 'Hello Title', FALSE);
        $this->assertPattern('/<title>Hello Title<\/title>/', $markup);
        $this->assertNoPattern('/<h1>Hello Title<\/h1>/', $markup);
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestResolvePathSymbols extends TemplarUnitTestCase {
    protected $cascade = NULL; // gets proxy of TemplarCascadeFramework
    function setUp() {
        TemplarUnitTestCase::setUp();
        $templar = &new MockTemplarPHP();
        $this->cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
    }
    function testNoChange() {
        $path = $this->cascade->resolvePathSymbols('a/b/c');
        $this->assertEqual($path, 'a/b/c');

        $path = $this->cascade->resolvePathSymbols('/a/b/c');
        $this->assertEqual($path, '/a/b/c');

        $path = $this->cascade->resolvePathSymbols('/');
        $this->assertEqual($path, '/');

        $path = $this->cascade->resolvePathSymbols('');
        $this->assertEqual($path, '');
    }
    function testCurrentFolderReferences() {
        $path = $this->cascade->resolvePathSymbols('./');
        $this->assertEqual($path, '');

        $path = $this->cascade->resolvePathSymbols('/./');
        $this->assertEqual($path, '/');

        $path = $this->cascade->resolvePathSymbols('/./a/b/c');
        $this->assertEqual($path, '/a/b/c');

        $path = $this->cascade->resolvePathSymbols('././a/b/c');
        $this->assertEqual($path, 'a/b/c');

        $path = $this->cascade->resolvePathSymbols('a/./b/c');
        $this->assertEqual($path, 'a/b/c');
    }
    function testParentFolderReferences() {
        $path = $this->cascade->resolvePathSymbols('a/b/../c');
        $this->assertEqual($path, 'a/c');

        $path = $this->cascade->resolvePathSymbols('/a/b/../c');
        $this->assertEqual($path, '/a/c');

        $path = $this->cascade->resolvePathSymbols('a/../../b');
        $this->assertNull($path);

        // CURRENTLY SUPPORTS FULL RESOLUTION ONLY, NOT PARTIAL AS BELOW:
        // $path = $cascade->resolvePathSymbols('a/../../b');
        // $this->assertTrue($path === '../b');
        // IMPLEMENTING THIS IS PROBABLY A BAD IDEA
    }
    function testParentAndCurrentFolderReferences() {
        $path = $this->cascade->resolvePathSymbols('a/./b/../c');
        $this->assertEqual($path, 'a/c');

        $path = $this->cascade->resolvePathSymbols('/a/./b/../c');
        $this->assertEqual($path, '/a/c');

        $path = $this->cascade->resolvePathSymbols('./a/b/../c');
        $this->assertEqual($path, 'a/c');
    }
    function testExtraSlashes() {
        $path = $this->cascade->resolvePathSymbols('//'); // double
        $this->assertEqual($path, '/');

        $path = $this->cascade->resolvePathSymbols('.//.//.//'); // relative mess
        $this->assertEqual($path, '');

        $path = $this->cascade->resolvePathSymbols('//.//.//'); // absolute mess
        $this->assertEqual($path, '/');

        $path = $this->cascade->resolvePathSymbols('a/b//c'); // double slashes
        $this->assertEqual($path, 'a/b/c');

        $path = $this->cascade->resolvePathSymbols('//a/b/c'); // leading doubles
        $this->assertEqual($path, '/a/b/c');

        $path = $this->cascade->resolvePathSymbols('a/b/c///'); // trailing doubles
        $this->assertEqual($path, 'a/b/c/');
    }
    function testAlternateDelimiter() {
        $path = $this->cascade->resolvePathSymbols('\\a\\b\\..\\c', '\\');
        $this->assertEqual($path, '\\a\\c');

        $path = $this->cascade->resolvePathSymbols('.|a|..|b|c', '|');
        $this->assertEqual($path, 'b|c');
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestGetParentDir extends CascadeUnitTestCase {
    function testBasicGetParent() {
        $cascade = $this->cascade;

        $parent = $cascade->getParentDirName('grandparent/parent/current/filename.html');
        $this->assertEqual($parent, 'grandparent/parent/');

        $parent = $cascade->getParentDirName('grandparent/parent/current/');
        $this->assertEqual($parent, 'grandparent/parent/');

        $parent = $cascade->getParentDirName('grandparent/parent/');
        $this->assertEqual($parent, 'grandparent/');

        $parent = $cascade->getParentDirName('/grandparent/parent/');
        $this->assertEqual($parent, '/grandparent/');

        $parent = $cascade->getParentDirName('/grandparent/');
        $this->assertEqual($parent, '/');

        $parent = $cascade->getParentDirName('grandparent/');
        $this->assertIdentical($parent, '', "Should be empty string, not null.");

        $parent = $cascade->getParentDirName('/filename.html');
        $this->assertNull($parent);

        $parent = $cascade->getParentDirName('filename.html');
        $this->assertNull($parent);

        $parent = $cascade->getParentDirName('/');
        $this->assertNull($parent);
    }
}

/**********************************************************************
 * Test bubbleOnce request and path calls.
 *********************************************************************/
class TestBubbleOnce extends CascadeUnitTestCase {
    function testBasicBubbleOnce() {
        $cascade = $this->cascade;

        $parent = $cascade->bubbleOnce('grandparent/parent/current/filename.html');
        $this->assertEqual($parent, 'grandparent/parent/filename.html');

        $parent = $cascade->bubbleOnce('grandparent/parent/current/index');
        $this->assertEqual($parent, 'grandparent/parent/index');

        $parent = $cascade->bubbleOnce('/grandparent/parent/index.php');
        $this->assertEqual($parent, '/grandparent/index.php');

        $parent = $cascade->bubbleOnce('/grandparent/index');
        $this->assertEqual($parent, '/index');

        $parent = $cascade->bubbleOnce('grandparent/index');
        $this->assertEqual($parent, 'index');

        $parent = $cascade->bubbleOnce('index.html');
        $this->assertNull($parent);

        $parent = $cascade->bubbleOnce('/index');
        $this->assertNull($parent);
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestGetBubbledPath extends TemplarUnitTestCase {
    protected $cascade = NULL; // gets TemplarCascadeFramework proxy
    function setUp() {
        TemplarUnitTestCase::setUp();
        $templar = &new MockTemplarPHP();
        $this->cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
        mkdir('child/', 0777);
        mkdir('child/grandchild/', 0777);
        file_put_contents('foo.html', '');
        file_put_contents('child/bar.php', '');
        file_put_contents('child/bar.html', '');
        file_put_contents('child/bar.xyz', '');
        file_put_contents('child/grandchild/foo.php', '');
    }
    function tearDown() {
        @unlink('foo.html');
        @unlink('child/bar.php');
        @unlink('child/bar.html');
        @unlink('child/bar.xyz');
        @unlink('child/grandchild/foo.php');
        rmdir('child/grandchild/');
        rmdir('child/');
        TemplarUnitTestCase::tearDown();
    }
    /* requests do not have file extensions */
    function testRequestBubbling() {
        $path = $this->cascade->getBubbledPath('child/grandchild/bar');
        $this->assertEqual($path, 'child/bar.php');

        $path = $this->cascade->getBubbledPath('child/grandchild/foo');
        $this->assertEqual($path, 'child/grandchild/foo.php');

        $path = $this->cascade->getBubbledPath('child/foo');
        $this->assertEqual($path, 'foo.html');
    }
    /* paths include file extensions*/
    function testPathBubbling() {
        $path = $this->cascade->getBubbledPath('child/grandchild/bar.html');
        $this->assertEqual($path, 'child/bar.html');

        $path = $this->cascade->getBubbledPath('child/grandchild/bar.php');
        $this->assertEqual($path, 'child/bar.php');

        $path = $this->cascade->getBubbledPath('child/grandchild/foo.html');
        $this->assertEqual($path, 'foo.html');
    }
    /* test for requests and paths that do not exist */
    function testNotFound() {
        $path = $this->cascade->getBubbledPath('child/grandchild/baz');
        $this->assertNull($path);

        $path = $this->cascade->getBubbledPath('child/grandchild/foo.abc');
        $this->assertNull($path);
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestDefault404NotFound extends CascadeUnitTestCase {
    function testDefaultMessage() {
        $request = 'dummy_request';
        $cascade = $this->cascade;
        $cascade->templar->envHost = 'example.com';
        $cascade->templar->envScheme = 'http';
        $cascade->templar->envWebRoot = '/web_root/';
        $markup = $cascade->getErrorMarkup('404_not_found', $request);
        $this->assertPattern('/http:\/\/example.com\/web_root\/dummy_request/', $markup);
        $this->assertPattern('/<title>.*404 Not Found.*<\/title>/i', $markup);
    }
}

class TestCustom404NotFound extends TemplarUnitTestCase {
    protected $cascade = NULL; //  gets proxy of TemplarCascadeFramework
    function setUp() {
        TemplarUnitTestCase::setUp();

        $templar = &new MockTemplarPHP();
        $templar->envHost = 'example.com';
        $templar->envScheme = 'http';
        $templar->envWebRoot = '/web_root/';
        $this->cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));

        mkdir('child/', 0777);
        file_put_contents('404_not_found.html', 'PARENT DIR FILE');
        file_put_contents('child/404_not_found.html', 'CHILD DIR CONTENTS');
    }
    function tearDown() {
        @unlink('child/404_not_found.html');
        @unlink('404_not_found.html');
        rmdir('child/');
        TemplarUnitTestCase::tearDown();
    }
    function testCustomErrorDocInParent() { // bubbles-up from grandchild
        $request = 'child/grandchild/dummy_request';
        $markup = $this->cascade->getErrorMarkup('404_not_found', $request);
        $this->assertEqual($markup, 'CHILD DIR CONTENTS');
    }
    function testCustomErrorDocCurrent() {
        $request = 'child/dummy_request';
        $markup = $this->cascade->getErrorMarkup('404_not_found', $request);
        $this->assertEqual($markup, 'CHILD DIR CONTENTS');

        $request = 'dummy_request';
        $markup = $this->cascade->getErrorMarkup('404_not_found', $request);
        $this->assertEqual($markup, 'PARENT DIR FILE');
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestGetMarkup extends TemplarUnitTestCase {
    function setUp() {
        TemplarUnitTestCase::setUp();
        $contents =
            '<html>
                <head><title>Hello World</title></head>
                <body><h1>Hello World</h1></body>
            </html>';
        file_put_contents('hello_world.html', $contents);

        $contents =
            '<html>
                <head><title></title></head>
                <body>
                    <h1>Hello<?php echo " PHP" ?> World</h1>
                </body>
            </html>';
        file_put_contents('php_example.php', $contents); // for php test

        $contents = 'Hello Text World';
        file_put_contents('text_example.txt', $contents); // for text test

        $contents = '<?php $a = 1; ?>';
        file_put_contents('baz.php', $contents); // for self-load test
        include_once('baz.php');
    }
    function tearDown() {
        @unlink('hello_world.html');
        @unlink('php_example.php');
        @unlink('text_example.txt');
        @unlink('baz.php');
        TemplarUnitTestCase::tearDown();
    }
    function testFromHtml() {
        $templar = &new MockTemplarPHP();
        $cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
        $path = $cascade->getPath('hello_world');
        $markup = $cascade->getMarkup($path);
        $this->assertPattern('/<title>Hello World<\/title>/', $markup);
    }
    function testFromText() {
        $templar = &new MockTemplarPHP();
        $cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
        $path = $cascade->getPath('text_example');
        $markup = $cascade->getMarkup($path);
        $this->assertPattern('/Hello Text World/', $markup);
    }
    function testFromCode() {
        $templar = &new MockTemplarPHP();
        $cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
        $path = $cascade->getPath('php_example');
        $markup = $cascade->getMarkup($path);
        $this->assertPattern('/Hello PHP World/', $markup);
    }
    function testMissingFile() {
        $templar = &new MockTemplarPHP();
        $cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
        $cascade->request = 'some_missing_file';
        $path = $cascade->getPath($cascade->request);
        $markup = $cascade->getMarkup($path);
        $this->assertPattern('/404 Not Found/i', $markup);
    }
    function testSelfLoad() {
        $templar = &new MockTemplarPHP();
        $templar->envFileRoot = getcwd() . '/';
        $cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
        $markup = $cascade->getMarkup('baz.php'); // baz.php is included in setUp()
        $this->assertPattern('/403 Forbidden/i', $markup);
        //$this->assertPattern("/Don't cross the streams. It would be bad./", $markup);
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestGetMimeTypes extends CascadeUnitTestCase {
    function testCheckTypes() {
        $result = $this->cascade->getMimeTypes('xml');
        $this->assertEqual(count($result), 3);
        $this->assertTrue(in_array('application/xhtml+xml', $result));
        $this->assertTrue(in_array('application/xml', $result));
        $this->assertTrue(in_array('text/xml', $result));

        $result = $this->cascade->getMimeTypes('html');
        $this->assertEqual(count($result), 1);
        $this->assertTrue(in_array('text/html', $result));

        $result = $this->cascade->getMimeTypes('xml_or_html');
        $this->assertEqual(count($result), 4);
        $this->assertTrue(in_array('application/xhtml+xml', $result));
        $this->assertTrue(in_array('application/xml', $result));
        $this->assertTrue(in_array('text/xml', $result));
        $this->assertTrue(in_array('text/html', $result));

        $result = $this->cascade->getMimeTypes('print');
        $this->assertEqual(count($result), 2);
        $this->assertTrue(in_array('application/xhtml+xml', $result));
        $this->assertTrue(in_array('application/vnd.pwg-xhtml-print+xml', $result));

        $result = $this->cascade->getMimeTypes('mobile');
        $this->assertEqual(count($result), 3);
        $this->assertTrue(in_array('application/vnd.wap.xhtml+xml', $result));
        $this->assertTrue(in_array('application/xhtml+xml', $result));
        $this->assertTrue(in_array('text/html', $result));

        $result = $this->cascade->getMimeTypes('dummy_type'); // unknown
        $this->assertIdentical($result, array());
    }
}
/**********************************************************************
 *
 *********************************************************************/
class TestGetDoctypeInfo extends CascadeUnitTestCase {
    function testDomAndStringInput() {
        /* test with doctype arg */
        $doctype = DOMImplementation::createDocumentType('html', '-//W3C//DTD HTML 4.01//EN');
        $result = $this->cascade->getDoctypeInfo($doctype);
        $this->assertIdentical($result['family'], array(0));
        $this->assertEqual($result['mime'], array('text/html'));

        /* test with string arg (where string is public doctype id) */
        $result = $this->cascade->getDoctypeInfo('-//W3C//DTD HTML 4.01//EN');
        $this->assertIdentical($result['family'], array(0));
        $this->assertEqual($result['mime'], array('text/html'));
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestGetDom extends TemplarUnitTestCase {
    function setUp() {
        TemplarUnitTestCase::setUp();
        $contents =
            '<html>
                <head><title></title></head>
                <body>
                    <h1>Hello World</h1>
                    <p>Paragraph one.</p>
                    <p>Paragraph two.</p>
                </body>
            </html>';
        file_put_contents('plain_markup.html', $contents);

        $contents =
            '<html>
                <head><title></title></head>
                <body>
                    <h1>Hello World</h1>
                    <p>Paragraph one.</p>
                    <p>Paragraph two.</p>
                    <p>&bull; &copy; &mdash;</p>
                </body>
            </html>';
        file_put_contents('entity_markup.html', $contents);
    }
    function tearDown() {
        @unlink('plain_markup.html');
        @unlink('entity_markup.html');
        TemplarUnitTestCase::tearDown();
    }
    function testPlainHtml() {
        $templar = &new MockTemplarPHP();
        $cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));

        $path = $cascade->getPath('plain_markup');
        $markup = $cascade->getMarkup($path);
        $dom = $cascade->getDom($markup);
        $elements = $dom->getElementsByTagName('p');
        $this->assertEqual($elements->length, 2);
    }
    function testHtmlWithEntities() {
        $templar = &new MockTemplarPHP();
        $cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));

        $path = $cascade->getPath('entity_markup');
        $markup = $cascade->getMarkup($path);
        $dom = $cascade->getDom($markup);
        $elements = $dom->getElementsByTagName('p');
        $this->assertEqual($elements->length, 3);
    }
}

class TestGetDomErrors extends TemplarUnitTestCase {
    protected $cascade = NULL; // gets instance of TemplarCascadeFramework proxy
    function setUp() {
        TemplarUnitTestCase::setUp();
        $contents =
            '<html>
                <head><title></title></head>
                <body>
                    <h1Hello World</h1>
                    <p>Paragraph one.</p>
                    <p>Paragraph two.</p>
                </body>
            </html>';
        file_put_contents('error_markup.html', $contents);

        $templar = &new MockTemplarPHP();
        $templar->envScheme = 'http';
        $templar->envHost = 'localhost';
        $templar->envWebRoot = '/test/';
        $this->cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
    }
    function tearDown() {
        @unlink('error_markup.html');
        TemplarUnitTestCase::tearDown();
    }
    function testAsExampleDotCom() { // TODO: move to _error_500_bad_markup() test
        $request = 'error_markup';
        $this->cascade->templar->envHost = 'example.com'; // <- testing as example.com
        $path = $this->cascade->getPath($request);
        $markup = $this->cascade->getMarkup($path);
        $dom = $this->cascade->getDom($markup, $path);
        $pat = '/href="http:\/\/validator.w3.org\/check\?uri=http%3A%2F%2Fexample.com%2Ftest%2F'.$request.'.html"/';
        $this->assertPattern($pat, $dom->saveHTML());
    }
    function testAsLocalhost() { // TODO: move to _error_500_bad_markup() test
        $request = 'error_markup';
        $this->cascade->templar->envHost = 'localhost'; // <- testing as localhost
        $path = $this->cascade->getPath($request);
        $markup = $this->cascade->getMarkup($path);
        $dom = $this->cascade->getDom($markup, $path);
        $pat = '/href="http:\/\/validator.w3.org\/#validate_by_input"/';
        $this->assertPattern($pat, $dom->saveHTML());
        //echo $dom->saveHTML();
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestGetCommands extends TemplarUnitTestCase {
    function setUp() {
        TemplarUnitTestCase::setUp();
        $contents =
            '<html>
                <head>
                    <title></title>
                    <meta name="description" content="A test file." />
                    <meta name="templar:nocache" content="" />
                    <meta name="templar:template" content="bar" />
                    <meta name="dummy_prefix:dummy_command" content="baz" />
                </head>
                <body>
                    <h1>Hello World</h1>
                </body>
            </html>';
        file_put_contents('foo.html', $contents);
    }
    function tearDown() {
        @unlink('foo.html');
        TemplarUnitTestCase::tearDown();
    }
    function testGetCommandsBasic() {
        $templar = &new MockTemplarPHP();
        $cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
        $request = 'foo';
        $path = $cascade->getPath($request);
        $markup = $cascade->getMarkup($path);
        $dom = $cascade->getDom($markup, $path);

        $this->assertEqual($cascade->commandPrefix, 'templar:');
        $commands = $cascade->getCommandNodes($dom);
        $this->assertIsA($commands, 'array');
        $this->assertEqual(count($commands), 2);

        $cascade->commandPrefix = 'dummy_prefix:';
        $commands = $cascade->getCommandNodes($dom);
        $this->assertIsA($commands, 'array');
        $this->assertEqual(count($commands), 1);
    }
}


/**********************************************************************
 *
 *********************************************************************/
class TestGetTemplatePath extends TemplarUnitTestCase {
    protected $cascade = NULL; //
    function setUp() {
        $templar = &new MockTemplarPHP();
        $this->cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
        TemplarUnitTestCase::setUp();
        file_put_contents('_foo.html', '');
        file_put_contents('_z_bar.html', '');
        file_put_contents('_zz_baz.html', '');
    }
    function tearDown() {
        @unlink('_foo.html');
        @unlink('_z_bar.html');
        @unlink('_zz_baz.html');
        TemplarUnitTestCase::tearDown();
    }
    function testLimitTwo_ZIndexZero() {
        $this->cascade->zIndexLevels = 2;
        $path = $this->cascade->getTemplatePath('', 'foo');
        $this->assertEqual($path, '_foo.html');
    }
    function testLimitZero_ZIndexZero() {
        $this->cascade->zIndexLevels = 0;
        $path = $this->cascade->getTemplatePath('', 'foo');
        $this->assertEqual($path, '_foo.html');
    }
    function testLimitTwo_ZIndexOne() {
        $this->cascade->zIndexLevels = 2;
        $path = $this->cascade->getTemplatePath('', 'bar');
        $this->assertEqual($path, '_z_bar.html');
    }
    function testLimitZero_ZIndexOne() {
        $this->cascade->zIndexLevels = 0;
        $path = $this->cascade->getTemplatePath('', 'bar');
        $this->assertNull($path); // bar (z-index 1) exceeds limit
    }
    function testLimitTwo_ZIndexTwo() {
        $this->cascade->zIndexLevels = 2;
        $path = $this->cascade->getTemplatePath('', 'baz');
        $this->assertEqual($path, '_zz_baz.html');
    }
    function testLimitOne_ZIndexTwo() {
        $this->cascade->zIndexLevels = 1;
        $path = $this->cascade->getTemplatePath('', 'baz');
        $this->assertNull($path); // baz (z-index 2) exceeds limit
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestSortTemplatePaths extends CascadeUnitTestCase {
    function testFolderDepth() {
        $paths = array(
            '_foo.html',
            'a/b/_foo.html',
            'a/_foo.html'
        );
        $paths = $this->cascade->sortTemplatePaths($paths);
        $sorted_order = array(
            'a/b/_foo.html',
            'a/_foo.html',
            '_foo.html'
        );
        $this->assertEqual($paths, $sorted_order);
    }
    function testZIndex() {
        $paths = array(
            '_z_bar.html',
            '_foo.php',
            '_zz_baz.html'
        );
        $paths = $this->cascade->sortTemplatePaths($paths);
        $sorted_order = array(
            '_zz_baz.html',
            '_z_bar.html',
            '_foo.php'
        );
        $this->assertEqual($paths, $sorted_order);
    }
    function testFolderDepthAndZIndex() {
        $paths = array(
            '_foo.php',
            'a/b/_z_baz.php',
            'a/_foo.html',
            '_z_bar.php',
            'a/b/_zz_foo.php'
        );
        $paths = $this->cascade->sortTemplatePaths($paths);
        $sorted_order = array(
            'a/b/_zz_foo.php',
            'a/b/_z_baz.php',
            'a/_foo.html',
            '_z_bar.php',
            '_foo.php'
        );
        $this->assertEqual($paths, $sorted_order);
    }
    function testOrderPreservation() {
        $paths = array('_apple.html', '_zebra.html');
        $paths = $this->cascade->sortTemplatePaths($paths);
        $sorted_order = array('_apple.html', '_zebra.html');
        $this->assertEqual($paths, $sorted_order, "Should preserve original order where possible");

        $paths = array('_zebra.html', '_apple.html');
        $paths = $this->cascade->sortTemplatePaths($paths);
        $sorted_order = array('_zebra.html', '_apple.html');
        $this->assertEqual($paths, $sorted_order, "Should preserve original order where possible");
    }
}

/**********************************************************************
 *
 *********************************************************************/
class TestGetAllTemplatePaths extends CascadeUnitTestCase {
    protected $cascade = NULL; //
    function setUp() {
        CascadeUnitTestCase::setUp();
        mkdir('child/', 0777);
        file_put_contents('_foo.html', '');
        file_put_contents('_z_bar.html', '');
        file_put_contents('child/_bar.html', '');
    }
    function tearDown() {
        @unlink('_foo.html');
        @unlink('_z_bar.html');
        @unlink('child/_bar.html');
        rmdir('child/');
        CascadeUnitTestCase::tearDown();
    }
    function testSingleCascadeTemplate() {
        $this->cascade->cascadingTemplates = array('foo');
        $template_paths = $this->cascade->getAllTemplatePaths('dummy_request');
        $this->assertEqual($template_paths, array('_foo.html'));
    }
    function testFixedTemplate() {
        $this->cascade->cascadingTemplates = array();
        $this->cascade->fixedTemplates = array('foo');
        $template_paths = $this->cascade->getAllTemplatePaths('child/dummy_request');
        $this->assertEqual($template_paths, array());
    }
    function testFixedTemplateParentDir() {
        $this->cascade->cascadingTemplates = array();
        $this->cascade->fixedTemplates = array('../bar');
        $template_paths = $this->cascade->getAllTemplatePaths('child/dummy_request');
        $this->assertEqual($template_paths, array('_z_bar.html'));
    }
    function testMultipleFixedTemplates() {
        $this->cascade->cascadingTemplates = array();
        $this->cascade->fixedTemplates = array('bar', '../foo');
        $template_paths = $this->cascade->getAllTemplatePaths('child/dummy_request');
        $this->assertEqual($template_paths, array('child/_bar.html', '_foo.html'));
    }
    function testDuplicateInFixedAndCascading() {
        $this->cascade->cascadingTemplates = array('foo', 'bar');
        $this->cascade->fixedTemplates = array('bar');
        $template_paths = $this->cascade->getAllTemplatePaths('child/dummy_request');
    }
    // TODO: Add tests for z-index ordering.
}



// TODO: Add unit tests for following
//applyTemplates()
//getDomLoadErrorMessage()
//_error_500_bad_markup()

/**********************************************************************
 *
 *********************************************************************/
/*
class BlankTestClass extends CascadeUnitTestCase {
    function testNameGoesHere() {
        $value = 2 + 2;
        $this->assertTrue($value == 4);
    }
}
*/


?>
